package com.chu.cloud.service.impl;

import com.chu.cloud.dto.OrderDelayPay;
import com.chu.cloud.dto.order.BaseOrderCreateDto;
import com.chu.cloud.dto.order.OrderResult;
import com.chu.cloud.dto.order.SeckillOrderCreateDto;
import com.chu.cloud.dto.order.SeckillResult;
import com.chu.cloud.entity.MerchantOrder;
import com.chu.cloud.entity.OrderDetail;
import com.chu.cloud.enums.OrderStatusEnums;
import com.chu.cloud.enums.RedisKeyPrefix;
import com.chu.cloud.feign.client.IActivityFeignClient;
import com.chu.cloud.rabbit.dead.DelayConstant;
import com.chu.cloud.rabbit.dead.DelayMessagePayload;
import com.chu.cloud.rabbit.fanout.send.RabbitFanoutSender;
import com.chu.cloud.repository.MerchantOrderRepository;
import com.chu.cloud.repository.OrderDetailRepository;
import com.chu.cloud.response.ResponseMessage;
import com.chu.cloud.service.base.AbstractOrderService;
import com.chu.cloud.util.ChuException;
import com.chu.cloud.util.JsonUtils;
import com.chu.cloud.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * @author: Tianshu.CHU
 * @Date: 2018/8/14 15:57
 * @Description:
 */
@Service("seckillOrder")
@Slf4j
public class SeckillOrderServiceImpl extends AbstractOrderService {

    @Autowired
    private MerchantOrderRepository orderRepository;

    @Autowired
    private OrderDetailRepository orderDetailRepository;

    @Autowired
    private IActivityFeignClient activityFeignClient;

    @Autowired
    private RabbitFanoutSender fanoutSender;

    @Override
    @Transactional
    public OrderResult generateOrder(Integer userId, BaseOrderCreateDto orderCreateDto) {
        SeckillOrderCreateDto seckillOrderDto = (SeckillOrderCreateDto) orderCreateDto;
        final String key = seckillOrderDto.getActId() + ":" + seckillOrderDto.getProductId();
        String orderNo = super.generateOrderNo(orderCreateDto.getOrderType(), seckillOrderDto.getShopId());
        BigDecimal price = RedisUtil.get(RedisKeyPrefix.SECKILL_PRICE, key, BigDecimal.class);
        OrderDetail orderDetail = super.packageOrderDetail(userId, orderNo, seckillOrderDto.getShopId(), seckillOrderDto.getProductId(),
                seckillOrderDto.getQuantity(), price);
        orderDetail.setActivityId(seckillOrderDto.getActId());
        orderDetailRepository.save(orderDetail);
        MerchantOrder order = super.packageOrder(userId, seckillOrderDto.getShopId(), seckillOrderDto, orderNo);
        order.setOrderStatus(OrderStatusEnums.CONFIRM);
        orderRepository.save(order);
        //减库存
        ResponseMessage<Boolean> response = activityFeignClient.reduceInventory(seckillOrderDto.getActId(), seckillOrderDto.getProductId(), seckillOrderDto.getQuantity());
        if (response.getCode() != 200) {
            //服务降级了,回滚redis库存
            String stocKey = RedisKeyPrefix.SECKILL_STOCKS.getPrefix() + key;
            RedisUtil.incr(stocKey, 1);
            throw new ChuException("下单失败");
        }
        if (response.getCode() == 200 && !response.getData()) {
            //库存不足,回滚订单
            RedisUtil.set(RedisKeyPrefix.SECKILL_OPEN_FLAG, key, false);
            throw new ChuException("库存不足,下单失败");
        }
        SeckillResult seckillResult = new SeckillResult(orderNo, seckillOrderDto.getProductId(), seckillOrderDto.getQuantity());
        RedisUtil.hSet(RedisKeyPrefix.SECKILL_RESULT_USER, userId, key, seckillOrderDto);
        Integer userPurchasedNum = RedisUtil.hGet(RedisKeyPrefix.SECKILL_RECORD_USER, userId, key);
        int curBuyNum = (userPurchasedNum == null ? 0 : userPurchasedNum) + seckillOrderDto.getQuantity();
        RedisUtil.hSet(RedisKeyPrefix.SECKILL_RECORD_USER, userId, key, curBuyNum);
//        //发送延迟队列,10分钟内支付订单
        OrderDelayPay delayPay = new OrderDelayPay(orderNo,userId,seckillOrderDto.getOrderType().getValue());
        DelayMessagePayload payload = new DelayMessagePayload(DelayConstant.FanoutQueue.SECKILL_TIMEOUT_PAY,
                DelayConstant.FanoutExchange.SECKILL_TIMEOUT_PAY_DEAD, DelayConstant.FanoutQueue.SECKILL_DEAD_LETTER,
                JsonUtils.obj2json(delayPay), 10 * 60 * 1000);
        fanoutSender.sendDelayMessage(payload);
        return seckillResult;
    }

}
